import store from './base/store'
import {
  BackgroundSprite,
  DownObstacleSprite,
  FloorSprite,
  ObstacleSprite,
  UpObstacleSprite
} from './runtime'
import { BirdSprite, ScoreSprite, StartSprite } from './player'

/**
 * 导演类
 * @description 游戏逻辑、循环、分数计算 + 精灵的创建、销毁、碰撞检测
 */
export default class Director {
  /** 单例对象 */
  private static instance: Director = null
  /** 主循环 */
  private timer: number = null
  /** 是否游戏结束 */
  public isGameOver = false
  /** 游戏速度 */
  public speed = 2
  /** 障碍物间隔 */
  public gap: number = store.canvas.height / 4

  /**
   * 获取单例
   * @returns 单例对象
   */
  public static getInstance(): Director {
    !Director.instance && (Director.instance = new Director())
    return Director.instance
  }

  /**
   * 点击游戏开始
   * @returns 无
   */
  public onClickStart(): void {
    // 1.数据类创建精灵
    store
      .put('background', new BackgroundSprite())
      .put('floor', new FloorSprite())
      .put('obstacles', [])
      .put('bird', new BirdSprite())
      .put('score', new ScoreSprite())
      .put('start', new StartSprite())
    // 2.导演类控制游戏结束
    this.isGameOver = false
    // 3.导演类创建障碍物
    this.createObstacle()
    // 4.导演类运行游戏
    this.run()
  }

  /**
   * 点击小鸟起飞
   * @returns 无
   */
  public onClickBird(): void {
    store.get<BirdSprite>('bird').fly()
  }

  /**
   * 游戏运行
   * @returns 无
   */
  private run = (): void => {
    // 一.游戏结束
    if (this.isGameOver === true) {
      // 1.开始按钮精灵 绘制
      store.get<StartSprite>('start').draw()
      // 2.清空数据
      store.destroy()
      cancelAnimationFrame(this.timer)
      return
    }

    // 二.游戏开始
    store.ctx.clearRect(0, 0, store.canvas.width, store.canvas.height)
    // 1.背景精灵类 绘制
    store.get<BackgroundSprite>('background').draw()
    // 2.障碍物精灵类 绘制
    const obstacles = store.get<ObstacleSprite[]>('obstacles')
    // 2-1.无障碍物：创建障碍物
    if (!obstacles.length) {
      this.createObstacle()
    } else {
      // 2-2.当前第1组障碍物x坐标 + 障碍物自身宽度 <= 0 且 总共2组障碍物：移除当前第1组障碍物
      if (obstacles[0].x + obstacles[0].w <= 0 && obstacles.length === 4) {
        obstacles.shift()
        obstacles.shift()
      }
      // 2-3.若 第1组障碍物x坐标 < (屏幕宽度 - 第1组障碍物宽度)/2 且 仅有1组障碍物
      if (
        obstacles[0].x <= (store.canvas.width - obstacles[0].w) / 2 &&
        obstacles.length === 2
      ) {
        this.createObstacle()
      }
    }
    obstacles.forEach(item => item.draw())
    // 3.地板精灵类 绘制
    store.get<FloorSprite>('floor').draw()
    // 4.计分器精灵类 计分+绘制
    store.get<ScoreSprite>('score').calc().draw()
    // 5.小鸟精灵类 绘制
    store.get<BirdSprite>('bird').draw()
    // 6.碰撞检测
    this.detectionRect()
    this.timer = requestAnimationFrame(this.run)
  }

  /**
   * 创建上下障碍物
   * @returns 无
   */
  private createObstacle(): void {
    const minTop = store.canvas.height / 4.8 // 上障碍物最低高度
    const maxTop = store.canvas.height / 2 // 上障碍物最高高度
    const top = minTop + Math.random() * (maxTop - minTop) // 上障碍物随机高度
    const obstacles = store.get<ObstacleSprite[]>('obstacles')
    store.put('obstacles', [
      ...obstacles,
      new UpObstacleSprite(top),
      new DownObstacleSprite(top)
    ])
  }

  /**
   * 碰撞检测（AABB法）
   * @returns 无
   */
  private detectionRect(): void {
    const bird = store.get<BirdSprite>('bird')
    const floor = store.get<FloorSprite>('floor')
    const obstacles = store.get<ObstacleSprite[]>('obstacles')

    // 小鸟边框模型
    const birdBorder = {
      top: bird.y,
      left: bird.x,
      right: bird.x + bird.w,
      bottom: bird.y + bird.h
    }

    // 地板边框模型
    const floorBorder = {
      top: floor.y,
      left: floor.x,
      right: floor.x + floor.w,
      bottom: floor.y + floor.h
    }

    // 1.地板碰撞
    if (birdBorder.bottom >= floorBorder.top) {
      this.isGameOver = true
      return
    }

    // 2.障碍物碰撞
    obstacles.forEach(item => {
      // 障碍物边框模型
      const obstacleBorder = {
        top: item.y,
        left: item.x,
        right: item.x + item.w,
        bottom: item.y + item.h
      }

      let isStrike = false
      // 鸟 进入 障碍物区域
      if (
        birdBorder.right >= obstacleBorder.left &&
        birdBorder.left <= obstacleBorder.right
      ) {
        if (item instanceof UpObstacleSprite) {
          // 1.上障碍物碰撞
          if (birdBorder.top <= obstacleBorder.bottom) {
            isStrike = true
          }
        } else if (item instanceof DownObstacleSprite) {
          // 2.下障碍物碰撞
          if (birdBorder.bottom >= obstacleBorder.top) {
            isStrike = true
          }
        }
      }
      // 撞击结束游戏
      if (isStrike) {
        this.isGameOver = true
        return
      }
    })
  }
}
